package top.vanchor.myblog2back.controller.user.gameCenter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RestController;
import top.vanchor.myblog2back.entity.BlogUser;
import top.vanchor.myblog2back.entity.gameCenter.PokerDdzBean;
import top.vanchor.myblog2back.service.IBlogUserService;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Ding
 * @create 2022/1/10 20:37
 */
@Slf4j
@Component
@CrossOrigin
@RestController
@ServerEndpoint("/gameCenter/pokerDdz/{sid}/{userId}")
public class PokerDdz {

    private static IBlogUserService iBlogUserService;

    @Autowired
    public void setIBlogUserService(IBlogUserService iBlogUserService) {
        PokerDdz.iBlogUserService = iBlogUserService;
    }

    /**
     * 房间号 -> 组成员信息
     */
    private static ConcurrentHashMap<String, List<Session>> groupMemberInfoMap = new ConcurrentHashMap<>();
    /**
     * 房间号 -> 在线人数
     */
    private static ConcurrentHashMap<String, Set<Integer>> onlineUserMap = new ConcurrentHashMap<>();

    /**
     * 发送给指定用户
     *
     * @param sid
     * @param userId
     * @param message
     * @throws IOException
     */
    public static void sendMessageTo(@PathParam("sid") String sid, @PathParam("userId") Integer userId, String message) throws IOException {
        List<Session> sessionList = groupMemberInfoMap.get(sid);
        Set<Integer> onlineUserList = onlineUserMap.get(sid);

        for (Session item : sessionList) {
            if (Integer.parseInt(String.valueOf(item.getRequestParameterMap().get("userId"))) == userId) {
                try {
                    System.err.println("这是你要发送的用户");
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }


    /**
     * 处理用户的请求，发送联机会话内容
     *
     * @param sid:房间号
     * @param userId：用户id
     * @param message：发送消息
     */
    @OnMessage
    public void onMessage(@PathParam("sid") String sid, @PathParam("userId") Integer userId, String message) {
        List<Session> sessionList = groupMemberInfoMap.get(sid);
        Set<Integer> onlineUserList = onlineUserMap.get(sid);
        /**
         * 封装信息体
         */
        BlogUser blogUser = iBlogUserService.getUserById(userId);
        PokerDdzBean msg = JSONObject.parseObject(message, PokerDdzBean.class);
        msg.setCount(onlineUserList.size());
        msg.setUsername(blogUser.getUName());
        msg.setAvatar(blogUser.getUAvatar());
        //判断对方是否在线
        if (onlineUserList.size() <= 1) {
            msg.setIsOnline(0);
        } else {
            msg.setIsOnline(1);
            if (msg.getData() != null) {
                JSONObject js = msg.getData();
                JSONObject obj = new JSONObject();
                int type = Integer.parseInt(String.valueOf(js.get("type")));
                if (type == 1) {
                    //初始化-发牌
                    obj = getInitPoker();
                    msg.setData(obj);
                } else if (type == -1) {
                    //叫分环节
                    obj = msg.getData();
                    msg.setData(obj);
                } else if (type == 2) {
                    //打牌阶段
                    obj = msg.getData();
                    List<Object> sendTemp = JSON.parseArray(obj.get("sendPoker").toString());
                    List<Object> lastTemp = JSON.parseArray(obj.get("lastPoker").toString());
                    int lastNum = Integer.parseInt(obj.get("lastNum").toString());

                    List<Map<String, Object>> sendPoker = new ArrayList<>();
                    List<Map<String, Object>> lastPoker = new ArrayList<>();

                    for (Object o : sendTemp) {
                        Map<String, Object> ret = (Map<String, Object>) o;
                        sendPoker.add(ret);
                    }
                    for (Object o : lastTemp) {
                        Map<String, Object> ret = (Map<String, Object>) o;
                        lastPoker.add(ret);
                    }

                    if (lastPoker.size() == 0) {
                        //上家不出牌，不是压牌，是任意牌
                        JSONObject resultJson = new JSONObject();
                        if (isLegal(null, sendPoker)) {
                            resultJson.put("lastPoker", sendPoker);
                            resultJson.put("code", 0);
                            resultJson.put("type", msg.getData().get("type"));
                            resultJson.put("isWin", lastNum == 0);
                            resultJson.put("pokerType", 0);
                        } else {
                            resultJson.put("code", -1);
                            resultJson.put("type", msg.getData().get("type"));
                        }
                        msg.setData(resultJson);
                    } else {
                        //压牌
                        JSONObject resultJson = new JSONObject();
                        if (sendPoker.size() == 0) {
                            //不要
                            resultJson.put("code", 0);
                            resultJson.put("type", msg.getData().get("type"));
                            resultJson.put("pokerType", 2);
                        } else {
                            if (isLegal(lastPoker, sendPoker)) {
                                resultJson.put("lastPoker", sendPoker);
                                resultJson.put("code", 0);
                                resultJson.put("isWin", lastNum == 0);
                                resultJson.put("type", msg.getData().get("type"));
                                resultJson.put("pokerType", 1);
                            } else {
                                resultJson.put("code", -1);
                                resultJson.put("type", msg.getData().get("type"));
                            }
                        }
                        msg.setData(resultJson);
                    }
                }
            }
        }
        //插入信息时间戳
        msg.setSendTime(String.valueOf((new Date()).getTime() / 1000));
        /**
         * 群发信息
         */
        sessionList.forEach(item -> {
            try {
                String text = JSONObject.toJSONString(msg);
                item.getBasicRemote().sendText(text);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });


    }

    /**
     * 建立连接调用的方法，群成员加入
     *
     * @param session
     * @param sid
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid, @PathParam("userId") Integer userId) {
        List<Session> sessionList = groupMemberInfoMap.computeIfAbsent(sid, k -> new ArrayList<>());
        Set<Integer> onlineUserList = onlineUserMap.computeIfAbsent(sid, k -> new HashSet<>());
        onlineUserList.add(userId);
        sessionList.add(session);
        // 发送上线通知
        sendInfo(sid, userId, onlineUserList.size(), 1, "上线通知");
    }

    /**
     * 关闭连接调用的方法，群成员退出
     *
     * @param session
     * @param sid
     */
    @OnClose
    public void onClose(Session session, @PathParam("sid") String sid, @PathParam("userId") Integer userId) {

        List<Session> sessionList = groupMemberInfoMap.get(sid);
        sessionList.remove(session);
        Set<Integer> onlineUserList = onlineUserMap.get(sid);
        onlineUserList.remove(userId);
        // 发送离线通知
        sendInfo(sid, userId, onlineUserList.size(), 2, "下线通知");
    }


    public void sendInfo(String sid, Integer userId, Integer onlineSum, Integer msgType, String info) {
        Set<Integer> onlineUserList = onlineUserMap.computeIfAbsent(sid, k -> new HashSet<>());

        // 获取该连接用户信息
        BlogUser blogUser = new BlogUser();
        try {
            blogUser = iBlogUserService.getUserById(userId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 发送通知
        PokerDdzBean msg = new PokerDdzBean();
        msg.setMsgType(msgType == null ? 0 : msgType);
        msg.setCount(onlineSum);
        msg.setUsername(blogUser.getUName());
        msg.setUserId(userId);
        msg.setAvatar(blogUser.getUAvatar());
        msg.setMsg(blogUser.getUName() + info);
        //判断对方是否在线
        if (onlineUserList.size() == 0) {
            msg.setIsOnline(0);
        } else {
            boolean isOnline = false;
            for (Integer integer : onlineUserList) {
                //为啥是userId，因为下线是下线者亲自申请的
                if (integer.equals(userId)) {
                    isOnline = true;
                    break;
                }
            }
            msg.setIsOnline(isOnline ? 1 : 0);
        }
        //插入信息时间戳
        msg.setSendTime(String.valueOf((new Date()).getTime() / 1000));
        // json对象转字符串
        String text = JSONObject.toJSONString(msg);
        onMessage(sid, userId, text);
    }

    /**
     * 传输消息错误调用的方法
     *
     * @param error
     */
    @OnError
    public void OnError(Throwable error) {
        System.err.println(error.toString());
        log.info("Connection error");
    }

    public Boolean isLegal(List<Map<String, Object>> lastPoker, List<Map<String, Object>> sendPoker) {
        if (lastPoker == null) {
            //出牌，判断牌型合法与否就好了
            if (sendPoker.size() == 1) {
                return PokerJudge.one(sendPoker);
            } else if (sendPoker.size() == 2) {
                return PokerJudge.two(sendPoker);
            } else if (sendPoker.size() == 3) {
                return PokerJudge.three(sendPoker);
            } else if (sendPoker.size() == 4) {
                return PokerJudge.four(sendPoker);
            }else if (sendPoker.size() == 5) {
                return PokerJudge.five(sendPoker);
            }else if (sendPoker.size() == 6) {
                return PokerJudge.six(sendPoker);
            }
        } else {
            //压牌，牌型合法与是否对版都要判断
            if (lastPoker.size() != sendPoker.size()) {
                //牌张数不一致,只有炸弹可以压不同张数的牌,炸弹只能有两张和四张
                if (sendPoker.size() == 2) {
                    return PokerJudge.numErrorTwo(sendPoker);
                } else if (sendPoker.size() == 4) {
                    return PokerJudge.numErrorFour(sendPoker, lastPoker);
                }
            } else {
                //牌张数一致,牌型分析即可
                if (sendPoker.size() == 1) {
                    return PokerJudge.one(sendPoker, lastPoker);
                } else if (sendPoker.size() == 2) {
                    return PokerJudge.two(sendPoker, lastPoker);
                } else if (sendPoker.size() == 3) {
                    return PokerJudge.three(sendPoker, lastPoker);
                } else if (sendPoker.size() == 4) {
                    return PokerJudge.four(sendPoker, lastPoker);
                }else if (sendPoker.size() == 5) {
                    return PokerJudge.five(sendPoker, lastPoker);
                }else if (sendPoker.size() == 6) {
                    return PokerJudge.six(sendPoker, lastPoker);
                }
            }
        }
        return false;
    }

    /**
     * 发牌算法
     *
     * @return
     */
    public JSONObject getInitPoker() {
        /**
         * step.1
         * 初始化牌盒
         * 并应用洗牌算法打乱
         */
        ArrayList<Map<String, Object>> pokerBox = new ArrayList<>();
        String[] colors = {"♦", "♥", "♠", "♣"};
        String[] numbers = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
        for (String color : colors) {
            int i = 0;
            for (String number : numbers) {
                Map<String, Object> poker = new HashMap<>();
                poker.put("c", color);
                poker.put("n", number);
                poker.put("s", 0);
                pokerBox.add(poker);
            }
        }
        //加入大小王
        for (int i = 0; i < 2; i++) {
            Map<String, Object> map = new HashMap<>();
            map.put("c", String.valueOf(i));
            map.put("n", String.valueOf(i));
            map.put("s", 0);
            pokerBox.add(map);
        }
        Collections.shuffle(pokerBox);
        /**
         * step.2
         * 发牌
         */
        ArrayList<Map<String, Object>> userA = new ArrayList<>();
        ArrayList<Map<String, Object>> userB = new ArrayList<>();
        ArrayList<Map<String, Object>> hand = new ArrayList<>();
        for (int i = 0; i < pokerBox.size(); i++) {
            if (i >= pokerBox.size() - 3) {
                //底牌
                hand.add(pokerBox.get(i));
            } else if (i % 3 == 0) {
                userA.add(pokerBox.get(i));
            } else if (i % 3 == 1) {
                userB.add(pokerBox.get(i));
            }
        }

        /**
         * step.3
         * 对每张牌进行排序
         * 自定义算法
         * 得到：userA1，userB1，hand
         */
        String[] sort = {"1", "0", "2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3"};
        ArrayList<Map<String, Object>> userA1 = new ArrayList<>();
        ArrayList<Map<String, Object>> userB1 = new ArrayList<>();
        for (String s : sort) {
            for (Map<String, Object> poker : userA) {
                if (poker.get("n").equals(s)) {
                    userA1.add(poker);
                }
            }
        }
        for (String s : sort) {
            for (Map<String, Object> poker : userB) {
                if (poker.get("n").equals(s)) {
                    userB1.add(poker);
                }
            }
        }

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userA", userA1);
        jsonObject.put("userB", userB1);
        jsonObject.put("hand", hand);
        jsonObject.put("type", 1);
        return jsonObject;
    }
}
